#include "videoplayer.h"
#include "sys_cache.h"
#include "sys_defe.h"
#include "sys_timer.h"
#include "jpegdec_main.h"
#include "stdlib.h"

#if AVI_PLAY_OS
#include "f1c100s_malloc.h"
#endif

volatile __align(4) u16 frame;
volatile __align(4) u8 frameup; // 视频播放时隙控制变量,当等于1的时候,可以更新下一帧视频
__align(4) u8 *saibuf[4];		// 音频缓冲帧,共4帧,4*5K=20K
volatile u8 saiplaybuf;			// 即将播放的音频帧缓冲编号

#define JPEG420 0
#define JPEG411 1
#define JPEG422 2
#define JPEG444 3
#define JPEG422T 4
#define JPEG400 5
#define JPEGERR 6

// 解码缓存相关
#define VIDEO_DEC_BUFF_NUM 3
int buff_b = VIDEO_DEC_BUFF_NUM;
int buff_con = 0; // 解码计数
__align(4) u8 *decoder_buff_y[VIDEO_DEC_BUFF_NUM];
__align(4) u8 *decoder_buff_c[VIDEO_DEC_BUFF_NUM];
// Timer视频中断
void TIMER2_VIDEO_ISR(void)
{
	Clear_interrupt(TIMER2); // 清中断
	frameup = 1;			 // video 帧时间到
}
// Timer视频初始化
void Sys_video_Init(int time_us)
{
	Sys_TimerX_Init(TIMER2, time_us * 100, TIMER2_VIDEO_ISR, 1);
}
// Timer视频关闭
void video_timer_close(void)
{
	Timer_disable(TIMER2);
}
/*--任务调用----------------------------*/
void AVI_Other_tasks(void)
{
	/*--裸机时处理短事件，不超过1ms--*/
	/*--OS时调用系统延时函数，1ms单位--*/
}
/////////////////////////////////////////////
// 分配内存
void *avi_malloc(int size)
{
	void *o = 0;
#if AVI_PLAY_OS
	o = f1c100s_malloc(size);
#else
	o = malloc(size);
	if ((unsigned int)o & 0x3)
	{
		sysprintf("malloc err...\r\n");
	}
#endif
	return o;
}

void avi_free(void *d)
{
#if AVI_PLAY_OS
	f1c100s_free(d);
#else
	free(d);
#endif
}
// 申请解码缓存
int malloc_decoder_buff(int w, int h)
{
	int i;
	buff_b = VIDEO_DEC_BUFF_NUM;
	buff_con = 0;
	for (i = 0; i < VIDEO_DEC_BUFF_NUM; i++)
	{
		decoder_buff_y[i] = (unsigned char *)video_pmalloc(get_y_len(w, h) / 1024 + 1, 1024); // 申请亮度内存[1024对齐]
		decoder_buff_c[i] = (unsigned char *)video_pmalloc(get_c_len(w, h) / 1024 + 1, 1024); // 申请色度内存[1024对齐]
		if ((decoder_buff_y[i] == 0) || (decoder_buff_c[i] == 0))
			return -1;
	}
	return 0;
}
// 释放解码缓存
void free_decoder_buff(void)
{
	int i;
	for (i = 0; i < VIDEO_DEC_BUFF_NUM; i++)
	{
		if (decoder_buff_y[i])
			video_pfree(decoder_buff_y[i]);
		if (decoder_buff_c[i])
			video_pfree(decoder_buff_c[i]);
	}
}
// 返回解码缓存编号
int get_decoder_buff(void)
{
	buff_b++;
	if (buff_b >= VIDEO_DEC_BUFF_NUM)
		buff_b = 0;
	return buff_b;
}
// 返回视频缓存编号
int get_video_buff(void)
{
	buff_con++;
	if (buff_con >= VIDEO_DEC_BUFF_NUM) // 解码满时返回
	{
		int i = buff_b;
		i--;
		if (i < 0)
			i = (VIDEO_DEC_BUFF_NUM - 1);
		return i;
	}
	else
		return -1;
}

// 显示当前播放时间
// favi:当前播放的视频文件
// aviinfo;avi控制结构体
void video_time_show(FIL *favi, AVI_INFO *aviinfo)
{
	static u32 oldsec; // 上一次的播放时间
	//	u8* buf;
	u32 totsec = 0;												  // video文件总时间
	u32 cursec;													  // 当前播放时间
	totsec = (aviinfo->SecPerFrame / 1000) * aviinfo->TotalFrame; // 歌曲总长度(单位:ms)
	totsec /= 1000;												  // 秒钟数.
	// cursec=((double)favi->fptr/favi->obj.objsize)*totsec;//当前播放到多少秒了? //读文件方式计时
	cursec = (aviinfo->SecPerFrame / 1000) * frame / 1000; // 当前播放到多少秒了?//帧数计时
	if (oldsec != cursec)								   // 需要更新显示时间
	{
		oldsec = cursec;
		video_sysprintf("Play Time:%02d:%02d:%02d/%02d:%02d:%02d\r\n", cursec / 3600, (cursec % 3600) / 60, cursec % 60, totsec / 3600, (totsec % 3600) / 60, totsec % 60); // 显示歌曲名字
	}
}

// 显示当前视频文件的相关信息
// aviinfo;avi控制结构体
void video_info_show(AVI_INFO *aviinfo)
{
	video_sysprintf("Channels:%d,SampleRate:%d\r\n", aviinfo->Channels, aviinfo->SampleRate); // 显示歌曲名字
	video_sysprintf("SecPerFrame:%d fps \r\n", 1000 / (aviinfo->SecPerFrame / 1000));		  // 显示歌曲名字
}
/*
播放TF卡Mjpeg压缩的AVI视频,音频格式为无压缩格式
视频解码后直接输出到DEFE-DEBE-TCON显示
可以缩放与调整位置
【
	videoplayer.h头文件设置
	视频定时器可以使用AV定时器或者普通定时器，使用AVS_TIME预定义
	VIDEO_LCD_W&VIDEO_LCD_H为设置显示器最大分辩率
】
x,y显示开始位置
w,h显示大小
pname文件路径
*/
int video_play_avi_mjpeg(int x, int y, int w, int h, u8 *pname)
{
	int defe_inin_f = 0;
	// int jpeg_w;
	// int jpeg_h;
	int jpeg_format;
	int defe_in_format;

	int yuv_w, yuv_h;
	u8 *framebuf; // 视频解码buf
	u8 *pbuf;	  // buf指针
	FIL *favi;
	u8 res = 0;
	u16 offset = 0;
	u32 nr;
	//	u8 key;
	u8 saisavebuf;
	//  int se=0;
	int nexts = 0;
	frame = 0;
	frameup = 0;
	video_sysprintf("-------------------------------------------------\r\n");
	video_sysprintf("play path: %s\r\n", pname);
	video_sysprintf("-------------------------------------------------\r\n");

	// 显示器检测
	if ((x + w) > VIDEO_LCD_W || (y + h) > VIDEO_LCD_H)
	{
		video_sysprintf("err[vedio]: window size or window pos error!\r\n");
		goto OUT_5;
	}

	// 申请缓存
	saibuf[0] = vedio_malloc(AVI_AUDIO_BUF_SIZE); // 申请音频内存
	saibuf[1] = vedio_malloc(AVI_AUDIO_BUF_SIZE); // 申请音频内存
	saibuf[2] = vedio_malloc(AVI_AUDIO_BUF_SIZE); // 申请音频内存
	saibuf[3] = vedio_malloc(AVI_AUDIO_BUF_SIZE); // 申请音频内存

	framebuf = (unsigned char *)video_pmalloc(AVI_VIDEO_BUF_SIZE / 1024 + 1, 1024);
	favi = (FIL *)vedio_malloc(sizeof(FIL)); // 申请favi内存
	vedio_memset(saibuf[0], 0, AVI_AUDIO_BUF_SIZE);
	vedio_memset(saibuf[1], 0, AVI_AUDIO_BUF_SIZE);
	vedio_memset(saibuf[2], 0, AVI_AUDIO_BUF_SIZE);
	vedio_memset(saibuf[3], 0, AVI_AUDIO_BUF_SIZE);

	// 检测缓存是否申请成功
	if (!saibuf[3] || !(u32)framebuf || !favi)
	{
		video_sysprintf("err[vedio]: memory error 1!\r\n");
		goto OUT_4;
	}

	// 开始读取文件
	res = video_f_open(favi, (char *)pname, FA_READ);

	if (res == 0)
	{
		pbuf = framebuf;

		res = video_f_read(favi, pbuf, AVI_VIDEO_BUF_SIZE, &nr); // 开始读取

		if (res)
		{
			video_sysprintf("err[vedio]: f_read error!\r\n");
			goto OUT_3;
		}
		// 开始avi解析
		res = avi_init(pbuf, AVI_VIDEO_BUF_SIZE); // avi解析
		if (res)
		{
			video_sysprintf("err[vedio]: %d\r\n", res);
			goto OUT_3;
		}
		if (malloc_decoder_buff(avix.Width, avix.Height) < 0)
		{
			video_sysprintf("err[vedio]: memory error 2!\r\n");
			goto OUT_3;
		}

		video_info_show(&avix);
		// 设置显示窗口
		video_set_video_window(x, y, w, h);
#ifndef AVS_TIME
		// 定时器初始化--10Khz计数频率,加1是100us
		video_Sys_video_Init(avix.SecPerFrame / 100 - 7);
#else
		// 定时器初始化--10Khz计数频率,加1是100us
		video_AVS_Time_Init(100);
		// 定时器开始
		video_AVS_Time_Start();
#endif
		offset = avi_srarch_id(pbuf, AVI_VIDEO_BUF_SIZE, (u8 *)"movi"); // 寻找movi ID
		if (avi_get_streaminfo(pbuf + offset + 4) == AVI_STREAM_ERR)	// 获取流信息
		{
			video_sysprintf("err[vedio]: streaminfo 1\r\n");
			goto OUT_2;
		}

		video_f_lseek(favi, offset + 12); // 跳过标志ID,读地址偏移到流数据开始处

		// JPG解码初始化
		vedio_MACC_Init();

		if (avix.SampleRate) // 音频初始化，有音频信息,才初始化
		{
			saiplaybuf = 0;
			saisavebuf = 0;
			vedio_WAV_Video_Play_Init(avix.Channels, avix.SampleRate);
		}

		while (1) // 播放循环
		{
			if (avix.StreamID == AVI_VIDS_FLAG) // 视频流
			{
				pbuf = framebuf;

				f_read(favi, pbuf, avix.StreamSize + 8, &nr); // 读入整帧+下一数据流ID信息

				if ((avix.StreamSize != 0) && ((avix.StreamSize + 8) == nr)) // 本帧无数据，不显示
				{
					/*--返回视频缓存编号--*/
					int dec_inx = get_decoder_buff();

					/*--解码JPEG成YUV图像--*/
					vedio_Jpeg_decoder_video(pbuf, avix.StreamSize,											  // JPEG输入设置
											 &yuv_w, &yuv_h,												  // 输出宽高
											 decoder_buff_y[dec_inx], decoder_buff_c[dec_inx], &jpeg_format); // YC缓存

					/*--DEFE转码与缩放图像到DEBE-TCON--显示*/
					int dis_inx = get_video_buff();
					/*传送到DE模块显示*/
					if (dis_inx >= 0)
					{
						if (defe_inin_f == 0)
						{
							defe_inin_f = 1;
							// DEFE初始化
							Video_Defe_Init();
							// LCD视频通道开
							__Enable_Layer_Video();
							// 设置视频格式
							if (jpeg_format == JPEG420)
							{
								defe_in_format = DE_SCAL_INYUV420;
							}
							else if ((jpeg_format == JPEG422) || (jpeg_format == JPEG444)) // 解码模块YUV444输出的YUV422
							{
								defe_in_format = DE_SCAL_INYUV422;
							}
							else if (jpeg_format == JPEG411)
							{
								defe_in_format = DE_SCAL_INYUV411;
							}
							else
							{
								goto OUT_1;
							}
							// 初始化DEFE
							Defe_Config_yuv_to_argb_video(defe_in_format, yuv_w, yuv_h, w, h, decoder_buff_y[dis_inx], decoder_buff_c[dis_inx]);
						}
						// 切换缓存
						Defe_conversion_buff(decoder_buff_y[dis_inx], decoder_buff_c[dis_inx]);
					}
				}
#ifndef AVS_TIME
				while (frameup == 0) // 等待时间到达
				{
					//+任务调用
					AVI_Other_tasks();
				}
				frameup = 0; // 清0
#else
				while (1) // 等待时间到达
				{
					if (video_AVS_Time_Read() >= (avix.SecPerFrame / 100 - 1))
					{
						video_AVS_Time_Start();
						break;
					}
				}
#endif
				frame++;
			}
			else // 音频流
			{
				video_time_show(favi, &avix); // 显示当前播放时间
				saisavebuf++;
				if (saisavebuf > 3)
					saisavebuf = 0;
				do
				{
					nr = saiplaybuf;
					if (nr)
						nr--;
					else
						nr = 3;
				} while (saisavebuf == nr); // 碰撞等待.

				f_read(favi, saibuf[saisavebuf], avix.StreamSize + 8, &nr); // 填充saibuf

				pbuf = saibuf[saisavebuf];
				// dma中断播放
			}
			if (avi_get_streaminfo(pbuf + avix.StreamSize)) // 读取下一帧 流标志
			{
				video_sysprintf("err[vedio]:frame error \r\n"); // 结束或错误，退出
				goto OUT_1;
			}
			// 退出播放
			if ((nExit == 0) && (nexts == 0))
				nexts = 1;
			if ((nExit == 1) && (nexts == 1))
				goto OUT_1; // 等弹起
		}
	}
	else
	{
		video_sysprintf("err[vedio]: f_open error!\r\n");
	}
OUT_1:
	Video_Defe_Exit();			  // DEFE退出
	__Disable_Layer_Video();	  // 关视频
	video_WAV_Video_Play_close(); // 关音频
OUT_2:
#ifndef AVS_TIME
	video_video_timer_close();
#else
	video_AVS_Time_Stop();
#endif
OUT_3:
	video_f_close(favi);
OUT_4:
	if (saibuf[0])
		vedio_free(saibuf[0]);
	if (saibuf[1])
		vedio_free(saibuf[1]);
	if (saibuf[2])
		vedio_free(saibuf[2]);
	if (saibuf[3])
		vedio_free(saibuf[3]);

	free_decoder_buff();
	if (framebuf)
		video_pfree(framebuf);
	if (favi)
		vedio_free(favi);
OUT_5:
	video_sysprintf("Quit playing ! \r\n"); // 结束或错误，退出
	video_sysprintf("\r\n\r\n\r\n");
	return res;
}
